// a = 10;
// console.log(global.a);
// console.log('1');
console.log("↓")
/*
    基本类型：
        number
        string
        boolean
        undefined
        null 
            underfined和 null区别：
                underfined 代表定义未赋值
                null 代表定义并赋值为 null
    对象(引用)类型：
        Object
        Function
        Array
    判断： 
        typeof  可以判断 undefined/number/string/boolean/function
            ****    不能判断 nul与 object、object与 array 
            返回数据类型的字符串表达式
        instanceof  判断对象具体类型
            a instanceof number
        ===     可以判断 undefined/null    
            全等于，数值、类型都相等

var b;
console.log(b, typeof b, b===undefined);
console.log(b == typeof b);
var c = null;
console.log('c = null');
console.log(typeof c, c === null);
var d = [1, 'ladk', console.log];
console.log("d = [1, 'ladk', console.log]");
console.log(typeof d, d === Array, d instanceof Array);
console.log(d[2], d[2]());
var e = { age : 12};
var f = e;
e = {name : 'bob', age : 13};
f.age = 14;
console.log(f.age, e.name, e.age);
*/

/*  函数的 prototype属性
        *每个函数都有个 prototype属性(即显式原型属性)，它默认指向一个Object空对象(即称为：原型对象)
        *原型对象中有一个属性constructor，它指向函数对象
    给原型对象添加属性(一般都是方法)
        *作用：函数的所有实例对象自动拥有原型中的属性(方法)
        对象的__proto__属性:创建对象时自动添加的，默认值为构造函数的prototype属性值
    函数的prototype属性值 == 对象的__proto__的属性值
    即 构造函数的显式原型的值 == 对象的隐式原型的值

    原型链：(隐式原型链)  用于查找对象的属性(方法)
        访问一个对象属性时：
            先在自身属性中查找，找到则返回
            若没有，则再沿着__proto__这条链向上查找，找到则返回
            如果最终没找到，则返回 undefined
        设置对象属性时：
            不会查找原型链，如果当前对象没有此属性，则直接添加此属性并设置其值
    
    instanceof 判断一个对象是否是一个函数的实例
        A instanceof B：若B函数的显式原型对象在A对象的原型链上，则返回true

function Fun(){

}
Fun.prototype.test1 = function(){
    console.log('-test1-') 
}
Fun.prototype.test2 = function(){
    console.log('-test2-') 
}
console.log(Fun.prototype.constructor === Fun)
console.log(Fun.prototype)
var fun = new Fun();
console.log(fun.__proto__)
console.log(Fun.prototype == fun.__proto__)
fun.test1()
fun.test2()
console.log(fun.toString())
*/
/* 测试题  
function A(){

}
A.prototype.n = 1
var b = new A()
A.prototype = {
    n:3,
    m:2
}
var c = new A()
console.log(b.n,b.m,c.n,c.m)

var F = function(){}
Object.prototype.a = function(){
    console.log('a()')
}
Function.prototype.b = function(){
    console.log('b()')
}
var f = new F()
f.a() 
f.b()  //error
F.a() 
F.b()

*/
/* 
    变量声明提升：
        通过var定义(声明)的变量，在定义语句之前就可以访问到
        值：undefined
    函数声明提升：
        通过function声明的函数，在之前就可以直接调用
        值：函数定义对象

    console.log(a)
    var a = 1
    f()
    function f(){
        console.log('f')
    }
    f()
    //g()      // error
    var g = function(){
        console.log('g')
    }
    g()



    function a(){ }
    var a
    console.log(typeof a)  // 'function'  

    if( !(b in window)){
        var b = 1
    }
    console.log(b) // undefined

    var c = 1
    function c(c) {
        console.log(c)
        var c = 3
    }
    c(2)   // error 
*/
    
/*
    执行上下文： 
        代码分类：
            全局代码
            函数(局部)代码
        执行上下文栈：
            队列先进先出，栈后进先出
            
        console.log(this) // {}
        console.log(a2) // [function: a2]
        console.log(a1) // undefined
        var a1 = 3
        function a2(a){
            console.log(a)
            console.log(arguments)  // 实参列表 伪数组
            
        }
        a2(1,2)  // 1

        var bar = function (x) {
            var b = 5
            foo(x + b)
        }
        var foo = function (y) {
            var c = 5
            console.log(a1 + c + y)
        }
        bar(10) // 23
*/

/* 
    作用域与作用域链：
    var fn1 = function() {
        console.log(fn1)
    }
    fn1() // [Function: fn1]
    var obj = {
        fn2 : function(){
            console.log(this.fn2)
            // console.log(fn2) error
        }
    }
    obj.fn2()  // [Function: fn2]
*/

/* 
    闭包: 1.是嵌套的内部函数、2.包含被引用变量(函数)的对象
        如何产生闭包：
            当一个嵌套的内部(子)函数引用了被嵌套的外部(父)函数的变量(函数)时，就产生了闭包
        闭包销毁：
            在嵌套的内部函数成为垃圾对象的时
        作用：
            使用函数内部的变量在函数执行完之后，仍然存活在内存中(延长了局部变量的生命周期);
            让函数外部可以操作(读写)到函数内部的数据(变量/函数)。    
            
        function fn1(){
            // 闭包产生
            var a = 2 
            function fn2() {
                var n = 0
                console.log("n:"+(++n))
                console.log("a:"+(++a))
            }
            return fn2
        }
        var f = fn1()
        f() // n:1 a:3
        f() // n:1 a:4
        f = null //闭包死亡
        fn1()() // n:1 a:3

        自定义JS模块：

        function myModule(){
            var msg = 'my msg'
            function doSome(){
                console.log("do some for " + msg)
            }
            function doOther(){
                console.log("do other for " + msg)
            }
            return {
                doSome, doOther
            }
        }

        var f = myModule()
        f.doSome()
        f.doOther();

        (function myModule2(window){
            var msg = 'my msg'
            function doSome(){
                console.log("do some for " + msg)
            }
            function doOther(){
                console.log("do other for " + msg)
            };
            window.myModule2 = {
                doSome: doSome,
                doOther: doOther
            } 
        })(window)

        var f2 = window.myModule2
        f2.doOther()
        f2.doSome()

        缺点：
            函数执行完之后，函数内的局部变量没有释放，占用内存时间会变长;
            容易造成内存泄漏
        能不用闭包就不用、或者及时释放
*/

/* 
    内存溢出:
        当程序运行需要的内存超过了剩余的内存时，就抛出内存溢出的错误
    内存泄漏:
        占用的内存没有及时释放
        内存泄漏积累多了就容易导致内存溢出
        常见内存泄漏：
            意外的全局变量、没有及时清理的计时器或回调函数、闭包
            function fn() {
                a = 3 // 全局变量a，函数执行完不会释放
                console.log(a)
            }
        
    var name = 'the window'
    var obj1 = {
        name: 'obj1 name',
        getName: function(){
            return function() {
                return name
            }
        }
    }
    console.log(obj1.getName()())   // the window

    var obj2 = {
        name: 'obj2 name',
        getName: function(){
            var that = this
            return function(){
                return that.name
            }
        }
    }
    console.log(obj2.getName()())   // obj2 name

    //究极绕

    function fun(n, o){
        console.log(o)
        return {
            fun:function(m){
                return fun(m,n)
            }
        }
    }
    console.log("a:")
    var a = fun(0) // undefined
    a.fun(1) // 0
    a.fun(2) // 0
    a.fun(3) // 0
    console.log("b:")
    var b = fun(0).fun(1).fun(2).fun(3) // undefined 0 1 2 
    console.log("c:")
    var c = fun(0).fun(1) // undefined 0
    c.fun(2) // 1
    c.fun(3) // 1
*/

/*
    对象创建模式

    // 1. Object 构造函数模式 先创建空Object对象 再动态添加属性/方法
    // 适用于 起始时不确定对象内部对象 --语句太多 过于繁琐
    var p = new Object()
    p.name = 'tommy'
    p.age = 12
    p.setName = function(name){
        this.name = name
    }
    p.setName('jane')
    console.log(p)
    // 2. 对象字面量模式 使用{ }创建对象 同时指定属性/方法
    // 适用于 起始时对象内部数据时确定的 --若创建多个对象则代码冗余
    var q = {
        name: 'machel',
        age: 13,
        setName(name){
            this.name = name
        }
    }
    q.setName("alpha")
    console.log(q)
    // 3. 工厂模式 通过工厂函数动态创建对象并返回 
    // 适用于 需要创建多个对象 --对象没有一个具体的类型 都是Object类型
    function creatPerson(name,age){
        return {
            name: name,
            age: age,
            setName(n){
                this.name = n
            }
        }
    }
    var r = creatPerson("jack",14)
    r.setName('john')
    console.log(r)
    // 4. 自定义构造函数模式 自定义构造函数 通过new创建对象
    // 适用于 需要创建多个类型确定的对象 --每个对象都有相同的数据 浪费内存
    function Person(name,age){
        this.name = name
        this.age = age
        this.setName = function(name){
            this.name = name
        }
    }
    var p1 = new Person('uzi',23)
    p1.setName('karm')
    console.log(p1)
    // 5. 构造函数+原型的组合模式 自定义构造函数 属性在函数中初始化 方法添加到原型上
    // 适用于 需要创建多个类型确定的对象
    function Person5(name, age){
        this.name = name
        this.age = age
    }
    Person5.prototype.setName = function(name){
        this.name = name
    }
    var p2 = new Person5('showlotus',20)
    p2.setName('秀莲')
    console.log(p2)

*/

/*
    原型链继承

    function Supper(){
        this.supProp = 'Supper property'
    }
    Supper.prototype.showSupper = function(){
        console.log(this.supProp)
    }

    function Sub(){
        this.subProp = 'Sub property'
    }
    // 子类型的原型为父类型的一个实例对象
    Sub.prototype = new Supper()
    // 让子类型的原型的constructor指向子类型
    Sub.prototype.constructor = Sub
    Sub.prototype.showSub = function(){
        console.log(this.subProp)
    }
    var sub = new Sub()
    sub.showSupper()
    sub.showSub()

    console.log(sub.constructor)

    // 借用构造函数继承(假的)
    function Person(name, age){
        this.name = name
        this.age = age
    }
    Person.prototype.setName = function(name){
        this.name = name
    }
    function Student(name, age, price){
        Person.call(this, name, age)
        this.price = price
    }
    Student.prototype = new Person() // 得到父元素的方法
    Student.prototype.constructor = Student //修正constructor属性
    Student.prototype.setPrice = function(price){
        this.price = price
    }
    var s = new Student('Tom', 20, 100)
    s.setName("newName")
    s.setPrice("200")
    console.log(s.name, s.age, s.price)
*/

/*
    进程与线程
        多进程运行  一应用程序可以同时启动多个实例运行
        多线程 ：在一个线程内 同时有多个线程运行
            优 ： 能有效提升CPU利用率 创建多进程开销
            劣 ： 线程间切换开销 死锁与状态同步问题
        单线程 ：
            优 ： 顺序编程简单易懂
            劣 ： 效率低
        JS ： 单线程运行
                使用H5的 Web Workers 可多线程运行
        浏览器 ；多线程运行
            多进程 ： chrome 新版IE
            单进程 ： Firefox 老版IE
            内核 ： 支持浏览器运行的最核心的程序
                Trident : 安全性更好 银行普遍采用
                Chrome、Safari ： webkit
                firfox : Gecko
                IE : Trident
                360、搜狗等国内浏览器 ： Trident + webkit

                内核组成模块
                    主线程 {
                        js引擎模块 ： 负责js程序的编译与运行
                        HTML、CSS文档解析模块 ： 负责页面文本的解析
                        DOM/CSS模块 ： 负责DOM/CSS在内存中的相关处理
                        布局和渲染模块 ： 负责页面的布局和效果的绘制(内存中的对象)
                        ...
                    }                
                    分线程 {
                        定时器模块 ： 负责定时器的管理
                        时间响应模块 ： 负责事件的管理
                        网络请求模块 ： 负责Ajax请求
                    }
                
                定时器的定时执行
                    并不是定时执行 也不能保证定时
                    alert 暂停当前主进程
                    var start = Date.now()
                    console.log(start)
                    setTimeout(function(){
                        console.log(Date.now()-start)
                    },200) 

            代码分类
                初始化代码 回调代码

            js引擎执行代码基本流程
                先执行初始化代码 包含一些特别的代码
                    设置定时器
                    绑定监听
                    发送Ajax请求
                后面在某个时刻才会执行回调代码

*/
/*
    Web Workers 多线程
*/

 


 